/**
 * The Slot class represents a signal slot.
 *
 * @author Robert Penner
 * @author Joa Ebert
 */
package org.osflash.signals;

import flash.errors.ArgumentError;
import flash.errors.Error;

class Slot implements ISlot {
	public var listener(getListener, setListener) : Dynamic;
	public var once(getOnce, never) : Bool;
	public var priority(getPriority, never) : Int;
	public var enabled(getEnabled, setEnabled) : Bool;
	public var params(getParams, setParams) : Array<Dynamic>;

	var _signal : IOnceSignal;
	var _enabled : Bool;
	var _listener : Dynamic;
	var _once : Bool;
	var _priority : Int;
	var _params : Array<Dynamic>;
	/**
	 * Creates and returns a new Slot object.
	 *
	 * @param listener The listener associated with the slot.
	 * @param signal The signal associated with the slot.
	 * @param once Whether or not the listener should be executed only once.
	 * @param priority The priority of the slot.
	 *
	 * @throws ArgumentError <code>ArgumentError</code>: Given listener is <code>null</code>.
	 * @throws Error <code>Error</code>: Internal signal reference has not been set yet.
	 */
	public function new(listener : Dynamic, signal : IOnceSignal, once : Bool = false, priority : Int = 0) {
		_enabled = true;
		_once = false;
		_priority = 0;
		_listener = listener;
		_once = once;
		_signal = signal;
		_priority = priority;
		verifyListener(listener);
	}

	/**
	 * @inheritDoc
	 */
	public function execute0() : Void {
		if(!_enabled) return;
		if(_once) remove();
		if(_params != null && _params.length > 0)  {
			_listener.apply(null, _params);
			return;
		}
		_listener();
	}

	/**
	 * @inheritDoc
	 */
	public function execute1(value : Dynamic) : Void {
		if(!_enabled) return;
		if(_once) remove();
		if(_params != null && _params.length > 0)  {
			_listener.apply(null, [value].concat(_params));
			return;
		}
		_listener(value);
	}

	/**
	 * @inheritDoc
	 */
	public function execute(valueObjects : Array<Dynamic>) : Void {
		if(!_enabled) return;
		if(_once) remove();
		if(_params != null && _params.length > 0)  {
			valueObjects = valueObjects.concat(_params);
		}
		var numValueObjects : Int = valueObjects.length;
		if(numValueObjects == 0)  {
			_listener();
		}

		else if(numValueObjects == 1)  {
			_listener(valueObjects[0]);
		}

		else if(numValueObjects == 2)  {
			_listener(valueObjects[0], valueObjects[1]);
		}

		else if(numValueObjects == 3)  {
			_listener(valueObjects[0], valueObjects[1], valueObjects[2]);
		}

		else  {
			_listener(valueObjects);
		}

	}

	/**
	 * @inheritDoc
	 * @throws ArgumentError <code>ArgumentError</code>: Given listener is <code>null</code>. Did you want to set enabled to false instead?
	 * @throws Error <code>Error</code>: Internal signal reference has not been set yet.
	 */
	public function getListener() : Dynamic {
		return _listener;
	}

	public function setListener(value : Dynamic) : Dynamic {
		if(null == value) throw new ArgumentError("Given listener is null.
Did you want to set enabled to false instead?");
		verifyListener(value);
		_listener = value;
		return value;
	}

	/**
	 * @inheritDoc
	 */
	public function getOnce() : Bool {
		return _once;
	}

	/**
	 * @inheritDoc
	 */
	public function getPriority() : Int {
		return _priority;
	}

	/**
	 * Creates and returns the string representation of the current object.
	 *
	 * @return The string representation of the current object.
	 */
	public function toString() : String {
		return "[Slot listener: " + _listener + ", once: " + _once + ", priority: " + _priority + ", enabled: " + _enabled + "]";
	}

	/**
	 * @inheritDoc
	 */
	public function getEnabled() : Bool {
		return _enabled;
	}

	public function setEnabled(value : Bool) : Bool {
		_enabled = value;
		return value;
	}

	/**
	 * @inheritDoc
	 */
	public function getParams() : Array<Dynamic> {
		return _params;
	}

	public function setParams(value : Array<Dynamic>) : Array<Dynamic> {
		_params = value;
		return value;
	}

	/**
	 * @inheritDoc
	 */
	public function remove() : Void {
		_signal.remove(_listener);
	}

	function verifyListener(listener : Dynamic) : Void {
		if(null == listener)  {
			throw new ArgumentError("Given listener is null.");
		}
		if(null == _signal)  {
			throw new Error("Internal signal reference has not been set yet.");
		}
	}

}

